package com.atguigu.gmall.item.controller;

import com.atguigu.gmall.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author lfy
 * @Description
 * @create 2022-12-08 14:03
 */
@Slf4j
@RestController
public class RedissonController {

    @Autowired
    RedissonClient redissonClient;

    String x = "abc";




    /**
     * 信号量； 能增能减
     * 停车场
     */
    @GetMapping("/init/park")
    public Result Semaphore(HttpServletRequest request){
        String remoteAddr = request.getRemoteAddr();
        log.info("远程访问init/park：{}",remoteAddr);
        RSemaphore semaphore = redissonClient.getSemaphore("xahfpark");
        semaphore.trySetPermits(5);


        return Result.ok("初始化停车场完成...");
    }

    @GetMapping("/car/park")
    public Result park(HttpServletRequest request) throws InterruptedException {
        String remoteAddr = request.getRemoteAddr();
        log.info("远程访问car/park：{}",remoteAddr);
        RSemaphore semaphore = redissonClient.getSemaphore("xahfpark");
        //要一个
        semaphore.acquire(1);

        return Result.ok("停车成功");
    }

    @GetMapping("/car/go")
    public Result cargo(HttpServletRequest request) throws InterruptedException {
        String remoteAddr = request.getRemoteAddr();
        log.info("远程访问car/go：{}",remoteAddr);
        RSemaphore semaphore = redissonClient.getSemaphore("xahfpark");
        //要一个
        semaphore.release(1);

        return Result.ok("车走了...");
    }


    /**
     * 闭锁； 只能减，减到0结束
     * 收集龙珠
     */
    @GetMapping("/shenlong")
    public Result shenlong(HttpServletRequest request) throws InterruptedException {
        String remoteAddr = request.getRemoteAddr();
        log.info("有人发请求：{}",remoteAddr);
        RCountDownLatch qilongzhu = redissonClient.getCountDownLatch("qilongzhu");

        qilongzhu.trySetCount(7L);
        log.info("等待召唤....");
        qilongzhu.await();
        return Result.ok("神龙.....");
    }

    @GetMapping("/longzhu")
    public Result longzhu(HttpServletRequest request){
        String remoteAddr = request.getRemoteAddr();
        log.info("有人发请求：{}",remoteAddr);
        RCountDownLatch qilongzhu = redissonClient.getCountDownLatch("qilongzhu");

        qilongzhu.countDown();
        return Result.ok("1颗到手...");
    }



    /**
     * 读写锁： 改数据
     * 读读： 无锁
     * 写写： 有锁
     * 写读： 有锁，读要等待
     * 读写： 有锁，写要等待
     *
     * @return
     */
    @GetMapping("/write")
    public Result write() throws InterruptedException {
        //1、获取读写锁
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("hahahaha");

        //2、获取写锁
        RLock wLock = rwLock.writeLock();

        try {
            wLock.lock();
            log.info("业务正在进行数据修改....");
            TimeUnit.SECONDS.sleep(15);
            x = UUID.randomUUID().toString();
            log.info("业务数据修改完成....");
        }finally {
            try {
                wLock.unlock();
            }catch (Exception e){}
        }

        return Result.ok(x);

    }

    @GetMapping("/read")
    public Result read() throws InterruptedException {
        //1、获取读写锁
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("hahahaha");

        //2、获取读锁
        RLock rLock = rwLock.readLock();

        //3、加读锁
        try {
            rLock.lock();
            log.info("业务正在远程读取数据中....");
            TimeUnit.SECONDS.sleep(10);
            log.info("业务远程读取数据完成....");
        }finally {
            rLock.unlock();
        }
        return Result.ok(x);
    }


    /**
     * 可重入锁
     * @return
     */
    @GetMapping("/redisson/lock")
    public Result lock(){
        //1、获取一把锁
        RLock lock = redissonClient.getLock("haha-lock");

        //2、加锁
        try {
            //1、阻塞式加锁； 一定要等到锁。  得到锁：锁的默认时间30s
            lock.lock(); //加解锁一定成对出现
            //2、阻塞式加锁(传了锁释放时间)； 一定要等到锁。  得到锁：锁的默认时间40s，而且没有续期功能；
//            lock.lock(40,TimeUnit.SECONDS);

            //3、尝试加锁：试一下； true：加锁成功；  默认时间30s; 自动续期
//            boolean b = lock.tryLock();
            //4、尝试加锁：10s内一直尝试。 true: 加锁成功(10s内返回true)  false：10s以后一定返回的是false   默认时间30s
            log.info("准备加锁....");
//            boolean tryLock = lock.tryLock(10, TimeUnit.SECONDS);
            //5、尝试加锁：10s内一直尝试。 true：加锁成功锁就20s有效
//            boolean tryLock = lock.tryLock(10, 20, TimeUnit.SECONDS);
//            if(tryLock){

            log.info("加锁成功：业务正在执行......");
            //xxxxx
            TimeUnit.SECONDS.sleep(60);
            log.info("业务执行完成......");
//            }else {
//                log.info("加锁失败...");
//            }



        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //3、解锁
            try {
                lock.unlock();  //同步解锁； 万一发现不是自己的锁，就不用解锁。
            }catch (Exception e){

            }

            log.info("解锁完成...");
//            if (lock.isLocked()) {
//                lock.unlock();
//            }

//            lock.unlockAsync(); //异步解锁

        }

        return Result.ok();
    }


    @GetMapping("/redisson/client")
    public Result client(){
        log.info("redissonclient: {}",redissonClient);
        return Result.ok();
    }
}
